package httpTest;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.junit.Before;
import org.junit.Test;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * 名称: HttpsTest.java <br>
 * 描述: <br>
 * 最近修改时间:2018/4/13 11:55 <br>
 *
 * @version [版本号, V1.0]
 * @since 2018/4/13 11:55
 * @author zhipingzhang  
 */
public class HttpsTest {



    @Test
    public void testReadCrt() throws Exception{

        String info;
        File file = new File("D:\\httpstest\\server.crt");
        InputStream inStream = new FileInputStream(file);
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        X509Certificate oCert = (X509Certificate)cf.generateCertificate(inStream);
        info = oCert.getSubjectDN().getName();
        System.out.println("证书拥有者:"+info);

    }


    /**
     * https post 双向认证测试 信任指定证书
     */
    @Test
    public void testBothHttpsGetTrustOne(){

        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketWithOneFactory()).build();

        HttpGet httpGet = new HttpGet("https://www.example.com:443");
        //HttpGet httpGet = new HttpGet("https://mail.quarkfinance.com");
        String result = null;

        try {

            CloseableHttpResponse response = httpclient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                result = EntityUtils.toString(entity, "UTF-8");
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭连接,释放资源
            try {
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println(result);

    }



    /**
     * https post 单向认证测试 信任指定证书
     */
    @Test
    public void testHttpsGetTrustOne(){

        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketWithOneFactory()).build();

        HttpGet httpGet = new HttpGet("https://www.example.com:443");
        //HttpGet httpGet = new HttpGet("https://mail.quarkfinance.com");
        String result = null;

        try {

            CloseableHttpResponse response = httpclient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                result = EntityUtils.toString(entity, "UTF-8");
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭连接,释放资源
            try {
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println(result);

    }





    /**
     * https post 单向认证测试 信任所有证书
     */
    @Test
    public void testHttpsGetTrustAll(){

        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory()).build();
        //CloseableHttpClient httpclient = HttpClients.createDefault();
        // 创建httppost
        //HttpPost httppost = new HttpPost("http://localhost:8082/financing/p2p_serv.action");//http联通
        HttpGet httpGet = new HttpGet("https://www.example.com:443");
        //HttpGet httpGet = new HttpGet("https://mail.quarkfinance.com");
        String result = null;

        try {

            CloseableHttpResponse response = httpclient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                result = EntityUtils.toString(entity, "UTF-8");
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭连接,释放资源
            try {
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println(result);

    }

    private static List<X509Certificate> certificateList = Lists.newArrayList();
    private static String certificatePath = "D:\\httpstest";

    @Before
    public void initCertificateList() throws Exception{

        File dir = new File(certificatePath);
        if(!dir.isDirectory()){
            throw new RuntimeException("证书目录错误");
        }
        File[] certificateFileS =  dir.listFiles();
        if(certificateFileS!=null&&certificateFileS.length>0 ){
            for(File certificateFile : certificateFileS){
                if(!certificateFile.isDirectory() && "crt".equals(certificateFile.getName().substring(certificateFile.getName().lastIndexOf(".")+1))){
                    InputStream inStream = null;
                    try {
                        inStream = new FileInputStream(certificateFile);
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }
                    CertificateFactory cf = CertificateFactory.getInstance("X.509");
                    X509Certificate oCert = (X509Certificate)cf.generateCertificate(inStream);
                    certificateList.add(oCert);
                }

            }
        }
        System.out.println("证书列表大小:"+certificateFileS.length);
    }

    private static boolean validateCertificate(X509Certificate targetCertificate){
        Preconditions.checkNotNull(targetCertificate);

        for(X509Certificate certificate :certificateList){
            if(certificate.equals(targetCertificate)){
                return true;
            }
        }
        return false;
    }



    /**
     * 创建SSL安全连接  双向
     * 信任指定
     * @return
     */
    private static SSLConnectionSocketFactory createBothSSLConnSocketWithOneFactory() {
        SSLConnectionSocketFactory sslsf = null;
        KeyStore trustStore = null;
        try {

            //信任指定证书
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {

                //所有认证会先进入这个方法，如果该方法返回false，则会继续进行内嵌认证方法
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {

                    return validateCertificate(chain[0]);
                }
            }).build();
            sslsf = new SSLConnectionSocketFactory(sslContext);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sslsf;
    }



    /**
     * 创建SSL安全连接
     * 信任指定
     * @return
     */
    private static SSLConnectionSocketFactory createSSLConnSocketWithOneFactory() {
        SSLConnectionSocketFactory sslsf = null;
        KeyStore trustStore = null;
        try {

            //信任指定证书
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {

                //所有认证会先进入这个方法，如果该方法返回false，则会继续进行内嵌认证方法
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {

                    return validateCertificate(chain[0]);
                }
            }).build();
            sslsf = new SSLConnectionSocketFactory(sslContext);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sslsf;
    }



    /**
     * 创建SSL安全连接
     * 信任所有证书
     * @return
     */
    private static SSLConnectionSocketFactory createSSLConnSocketFactory() {
        SSLConnectionSocketFactory sslsf = null;
        try {
            //信任所有证书
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {

                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return false;
                }
            }).build();
            sslsf = new SSLConnectionSocketFactory(sslContext);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sslsf;
    }
}
